/**
 * @file can_interface.c
 * @author YangSL (dalin@main.com)
 * @brief CAN协议通信数据接口文件
 * @version 0.0.1
 * @date 2022-09-29
 * 
 * @copyright Copyright (c) 2022
 * 
 */ 
#include "can_interface.h"
#include "bsp_can_bus.h"
#include "my_rtt_print_log.h"

typedef struct{
    bool m_enable;          /* 使能标志 */
    uint16 m_mqLenTx;       /* 发送长度 */
    uint16 m_mqLenRx;       /* 接收长度 */
    msgqueue_t m_mqTx;      /* 发送消息头 */
    msgqueue_t m_mqRx;      /* 接收消息头 */
    // CAN_TypeDef* m_can;
}CANInfo;

static CANInfo caninfo[CAN_TOTAL_NUM]={
    {true, 32, 32, NULL, NULL},
    {true, 32, 32, NULL, NULL}
};


/**
 * @brief 缓存CAN帧，将其放到队列中
 * 
 * @param p_can_msg 
 */
static void bufCanData(CanMessage* p_can_msg)
{
	uint8 port = 0;
	if (NULL == p_can_msg)
	{
		SEGGER_RTT_printf(0, "pointer p_can_msg is bad,file = %s, line = %d\n", __FILE__, __LINE__);
		return ;
	}

	// BaseType_t xHigherPriorityTaskWoken;
	if (caninfo[port].m_mqRx)
	{
        if (false == kernel_mq_send(caninfo[port].m_mqRx,p_can_msg,-2))
		{
			SEGGER_RTT_printf(0, "cmd can queue is err!\n");
		}
		// portYIELD_FROM_ISR(xHigherPriorityTaskWoken);//如果需要的话进行一次任务切换
	}
}

/**
 * @brief 配置并打开CAN
 * 
 * @param port 
 * @param baudrate 
 * @return true 
 * @return false 
 */
bool can_open(uint8 port, uint32 baudrate)
{
    if (port>=CAN_TOTAL_NUM)
    {
        return false;
    }

    canxInit(port, baudrate);

    /* 检查是否已经创建了队列 */
    if (caninfo[port].m_mqTx!=NULL || caninfo[port].m_mqRx!=NULL)
    {
        SEGGER_RTT_printf(0, "can is already open!!\n");
        return false;
    }
    caninfo[port].m_mqTx = kernel_mq_init(caninfo[port].m_mqLenTx,sizeof(CanMessage));
    caninfo[port].m_mqRx = kernel_mq_init(caninfo[port].m_mqLenRx,sizeof(CanMessage));
    if (caninfo[port].m_mqTx==NULL || caninfo[port].m_mqRx==NULL)
    {
        SEGGER_RTT_printf(0, "creat queue err: file %s on line %d\n", __FILE__, __LINE__);
        return false;
    }

    if (caninfo[port].m_mqRx)
	{
		cmdCanRxDataProcessCallback = bufCanData;
	}

    if(port == 0)
        SEGGER_RTT_printf(0, "CAN1 INIT!\n");
    else if(port == 1)
        SEGGER_RTT_printf(0, "CAN2 INIT!\n");
    return true;
}

/**
 * @brief 
 * 
 * @param port 
 * @param p_can_msg 
 * @return uint8 
 */
uint8 can_transmit(uint8 port, CanTxMsg *p_can_msg)
{
    uint32_t tx_mailbox = 0; // 获取空的发送邮箱号,HAL_CAN_AddTxMessage函数需要
    uint32_t free_tx_mailbox_num = 0;
    CAN_TxHeaderTypeDef tx_header;
	HAL_StatusTypeDef state;
    if (NULL == p_can_msg)
    {
        return 0xff;
    }

    if(p_can_msg->IDE == CAN_ID_STD)
    {
        tx_header.IDE = CAN_ID_STD;          // ID类型：扩展帧
        tx_header.StdId = p_can_msg->StdId; // 标准帧ID,最大11位
    }
        
    else 
    {
        tx_header.IDE = CAN_ID_EXT;          // ID类型：标准帧
        tx_header.ExtId = p_can_msg->ExtId;
    }

    tx_header.RTR = CAN_RTR_DATA;        // 帧类型：数据帧
    tx_header.DLC = p_can_msg->DLC;
    tx_header.TransmitGlobalTime = DISABLE;

    // TODO:1.考虑发送方式由阻塞式发送改为异步发送，利用CAN发送中断来处理
    // TODO:2.考虑增加RTOS系统回调函数，改为RTOS阻塞，避免阻塞低优先级任务，经测试此处发送阻塞可以达到0.3ms，如果总线出现异常阻塞时间会更高
    // 等待有空闲邮箱可用
    do
    {
        free_tx_mailbox_num = HAL_CAN_GetTxMailboxesFreeLevel(port == 0 ? &hcanx[CAN1_INDEX] : &hcanx[CAN2_INDEX]);
    }while (0 == free_tx_mailbox_num);

    if ((state = HAL_CAN_AddTxMessage(port == 0 ? &hcanx[CAN1_INDEX] : &hcanx[CAN2_INDEX], &tx_header, p_can_msg->Data, &tx_mailbox)) != HAL_OK)
    {
        // transmit request error
//        Error_Handler(__FILE__, __LINE__);
    }
	else
		return state;
		
    return 0;
}

/**
 * @brief 
 * 
 * @param port 
 * @param msg 
 * @return true 
 * @return false 
 */
bool can_send_msg(uint8 port, void* msg)
{
    CanTxMsg txMsg;
    CanMessage* canMsg = (CanMessage*)msg;
    if (port>=CAN_TOTAL_NUM || msg==NULL || caninfo[port].m_mqTx==NULL)
    {
        return false;
    }
    if (canMsg->m_dataLen>8)
    {
        return false;
    }

    if (canMsg->m_extend)
    {
        txMsg.ExtId = canMsg->m_canID;
        txMsg.IDE = CAN_ID_EXT;
    }
    else
    {
        txMsg.StdId = canMsg->m_canID;
        txMsg.IDE = CAN_ID_STD;
    }

    if (canMsg->m_remote)
    {
        txMsg.RTR = CAN_RTR_REMOTE;
        txMsg.DLC = 0;
    }
    else
    {
        uint8 i;
        txMsg.RTR = CAN_RTR_DATA;
        txMsg.DLC = canMsg->m_dataLen;

        for (i = 0; i < canMsg->m_dataLen; i++)
        {
            txMsg.Data[i] = canMsg->m_data[i];
        }
    }
    
    if (kernel_mq_size(caninfo[port].m_mqTx)==0)
    {
        if (can_transmit(port, &txMsg) != HAL_BUSY)
        {
            return true;
        }
    }
    return kernel_mq_send(caninfo[port].m_mqTx, &txMsg, 5);
}



/**
 * @brief 
 * 
 * @param port 
 * @param msg 
 * @return true 
 * @return false 
 */
//typedef struct {
//    uint32 m_canID; /* 标准帧标识 */
//    uint8 m_extend; /* 扩展帧标识 */
//    uint8 m_remote; /* 远程帧标识*/
//    uint8 m_dataLen;/* 数据长度 */
//    uint8 m_data[8];/* 数据buf */
//}CanMessage;
bool can_recv_msg(uint8 port, void* msg)
{
    CanMessage rxMsg;
    CanMessage* canMsg = (CanMessage*)msg;
    if (port>=CAN_TOTAL_NUM || msg==NULL || caninfo[port].m_mqRx==NULL)
    {
        return false;
    }
    if (!kernel_mq_recv(caninfo[port].m_mqRx, canMsg, 0))
    {
        return false;
    }

    return true;
}


